﻿using System;
using System.Collections.Generic;
using System.Text;
using Pixysoft.Framework.XSchEmA.Entity;
using System.Text.RegularExpressions;
using Pixysoft.Framework.XSchEmA.Sql;
using System.IO;

namespace Pixysoft.Framework.XSchEmA.Aspect
{
    class SQLiteSchemaAspect : ISchemaAspect
    {
        private const long max_text_length = 2147483647;
        private const long default_textlength = 400;
        private const int default_int_length = 38;

        List<string> dataTypeList;
        List<string> systemNameList;

        public SQLiteSchemaAspect()
        {
            dataTypeList = Pixysoft.EnumCoder.ToList<SQLiteDataTypeCollection>();
            systemNameList = Pixysoft.EnumCoder.ToList<SQLiteKeyWordCollection>();
        }


        public Pixysoft.Framework.XSchEmA.Entity.DataTypeSchema GetDefaultDataType()
        {
            return new DataTypeSchema(
            SQLiteDataTypeCollection.TEXT.ToString(), default_textlength, -1, -1);
        }

        public Pixysoft.Framework.XSchEmA.Entity.DataTypeSchema AutoCompleteDataType(string datatype)
        {
            if (datatype == null)
                throw new Exception("011001");

            if (!dataTypeList.Contains(datatype))
                return GetDefaultDataType();

            SQLiteDataTypeCollection datatypeEnum = Pixysoft.EnumCoder.ToEnum<SQLiteDataTypeCollection>(datatype);

            switch (datatypeEnum)
            {
                case SQLiteDataTypeCollection.INTEGER:
                case SQLiteDataTypeCollection.NUMERIC:
                case SQLiteDataTypeCollection.REAL:
                    return new DataTypeSchema(datatypeEnum.ToString(), -1, 10, -1);
                case SQLiteDataTypeCollection.TEXT:
                    return new DataTypeSchema(datatypeEnum.ToString(), default_textlength, -1, -1);
                case SQLiteDataTypeCollection.DATETIME:
                case SQLiteDataTypeCollection.NONE:
                default:
                    return new DataTypeSchema(datatypeEnum.ToString(), -1, -1, -1);
            }
        }

        public bool IsValidDataType(Pixysoft.Framework.XSchEmA.Entity.DataTypeSchema datatype)
        {
            datatype.Inspection();

            if (!dataTypeList.Contains(datatype.DataType.ToUpper()))
                return false;

            SQLiteDataTypeCollection datatypeEnum = Pixysoft.EnumCoder.ToEnum<SQLiteDataTypeCollection>(datatype.DataType);

            switch (datatypeEnum)
            {
                case SQLiteDataTypeCollection.INTEGER:
                    if (datatype.Precision < 1 || datatype.Precision > default_int_length)
                        return false;
                    break;

                case SQLiteDataTypeCollection.REAL:
                case SQLiteDataTypeCollection.NUMERIC:
                    if (datatype.Precision < 1 || datatype.Precision > default_int_length)
                        return false;
                    if (datatype.Scale != -1 && (datatype.Scale < 1 || datatype.Scale > datatype.Precision))
                        return false;
                    break;


                case SQLiteDataTypeCollection.TEXT:
                    if (datatype.Length < 1 || datatype.Length > max_text_length)
                        return false;
                    break;
                case SQLiteDataTypeCollection.DATETIME:
                case SQLiteDataTypeCollection.NONE:
                default:
                    break;
            }

            return true;
        }

        public bool IsUniqueDataType(Pixysoft.Framework.XSchEmA.Entity.DataTypeSchema datatype)
        {
            return false;
        }

        public string GetDotNetDataType(Pixysoft.Framework.XSchEmA.Entity.DataTypeSchema datatypeSchema)
        {
            datatypeSchema.Inspection();

            SQLiteDataTypeCollection type = Pixysoft.EnumCoder.ToEnum<SQLiteDataTypeCollection>(datatypeSchema.DataType);

            switch (type)
            {
                case SQLiteDataTypeCollection.INTEGER:
                    return "System.Int64";
                case SQLiteDataTypeCollection.NUMERIC:
                case SQLiteDataTypeCollection.REAL:
                    return "System.Double";
                case SQLiteDataTypeCollection.NONE:
                    return "System.Byte[]";
                case SQLiteDataTypeCollection.DATETIME:
                    return "System.DateTime";
                case SQLiteDataTypeCollection.TEXT:
                default:
                    return "System.String";
            }
        }

        public void TransformToGeneral(Pixysoft.Framework.XSchEmA.Entity.DatabaseSchema schema)
        {
            foreach (TableSchema table in schema.Tables)
            {
                foreach (ColumnSchema column in table.Columns)
                {

                    SQLiteDataTypeCollection type = Pixysoft.EnumCoder.ToEnum<SQLiteDataTypeCollection>(column.DataType.DataType);

                    switch (type)
                    {


                        case SQLiteDataTypeCollection.INTEGER:
                            column.DataType = new DataTypeSchema(DotNetDataType.Int64.ToString(), -1,
                                column.DataType.Precision, column.DataType.Scale, column.DataType.IsAutoIncrement);
                            break;

                        case SQLiteDataTypeCollection.NUMERIC:
                        case SQLiteDataTypeCollection.REAL:
                            column.DataType = new DataTypeSchema(DotNetDataType.Double.ToString(), -1,
                                column.DataType.Precision, column.DataType.Scale, column.DataType.IsAutoIncrement);
                            break;

                        case SQLiteDataTypeCollection.DATETIME:
                            column.DataType = new DataTypeSchema(DotNetDataType.DateTime.ToString(), -1,
                                   -1, -1, column.DataType.IsAutoIncrement);
                            break;

                        case SQLiteDataTypeCollection.NONE:
                            column.DataType = new DataTypeSchema(DotNetDataType.Byte.ToString(), -1, -1, -1, column.DataType.IsAutoIncrement);
                            break;

                        case SQLiteDataTypeCollection.TEXT:
                        default:
                            column.DataType = new DataTypeSchema(DotNetDataType.String.ToString(), column.DataType.Length, -1, -1, column.DataType.IsAutoIncrement);
                            break;

                    }
                }
            }
        }

        public void Transformation(Pixysoft.Framework.XSchEmA.Entity.DatabaseSchema database)
        {
            //要判断一些错误

            //1主键不能是TEXT，改成VERCHAR

            database.Info = new DatabaseInfo();

            database.Info.DatabaseType = DatabaseType.SQLite;

            foreach (TableSchema table in database.Tables)
            {
                foreach (ColumnSchema column in table.Columns)
                {
                    DotNetDataType type = Pixysoft.EnumCoder.ToEnum<DotNetDataType>(column.DataType.DataType);

                    switch (type)
                    {
                        case DotNetDataType.Boolean://2010-08-08 对应数字
                        case DotNetDataType.Char:
                        case DotNetDataType.Int32:
                        case DotNetDataType.Int64:
                            column.DataType = new DataTypeSchema(
                                SQLiteDataTypeCollection.INTEGER.ToString(), -1, default_int_length, -1, column.DataType.IsAutoIncrement);
                            break;

                        case DotNetDataType.Decimal:
                        case DotNetDataType.Single:
                        case DotNetDataType.Double:
                            column.DataType = new DataTypeSchema(SQLiteDataTypeCollection.NUMERIC.ToString(), -1,
                                column.DataType.Precision > default_int_length ? 53 : column.DataType.Precision,
                                column.DataType.Scale > column.DataType.Precision ? column.DataType.Precision : column.DataType.Scale,
                                column.DataType.IsAutoIncrement);
                            break;


                        case DotNetDataType.Byte:
                            column.DataType = new DataTypeSchema(SQLiteDataTypeCollection.NONE.ToString(), -1, -1, -1, column.DataType.IsAutoIncrement);
                            break;

                        case DotNetDataType.DateTime:
                            column.DataType = new DataTypeSchema(SQLiteDataTypeCollection.DATETIME.ToString(), -1, -1, -1, column.DataType.IsAutoIncrement);
                            break;


                        //case DotNetDataType.Boolean:
                        //case DotNetDataType.Char:
                        case DotNetDataType.String:
                        default:
                            column.DataType = new DataTypeSchema(SQLiteDataTypeCollection.TEXT.ToString(),
                             column.DataType.Length > max_text_length ? max_text_length : column.DataType.Length,
                             -1, -1, column.DataType.IsAutoIncrement);
                            break;
                    }
                }
            }
        }

        public List<string> GetDataTypeList()
        {
            return Pixysoft.EnumCoder.ToList<SQLiteDataTypeCollection>();
        }

        public List<string> GetDataTypeRegexList()
        {
            List<string> list = new List<string>();
            list.Add(@"[\w]+\([\d]+\)[,]{0,1}");
            list.Add(@"[\w]+\([\d]+[,\d]*\)[,]{0,1}");

            foreach (string type in Pixysoft.EnumCoder.ToList<SQLiteDataTypeCollection>())
                list.Add(type + "[,]{0,1}");

            return list;
        }

        public List<string> GetKeyWordsList()
        {
            return systemNameList;
        }

        public bool IsValidName(string name)
        {
            if (name == null)
                return false;

            if (name.Trim() == "")
                return false;

            if (systemNameList.Contains(name.ToUpper()))
                return false;

            if (name.Length > 30)
                return false;

            if (Regex.Match(name, "[a-z,A-Z]{1}[a-z,A-Z,1-9,_,$,#]*").Value != name)
                return false;

            return true;
        }

        public string ValidateDefaultValue(string input, Pixysoft.Framework.XSchEmA.Entity.DataTypeSchema datatype)
        {
            if (input == null)
                return null;

            SQLiteDataTypeCollection datatypeEnum = Pixysoft.EnumCoder.ToEnum<SQLiteDataTypeCollection>(datatype.DataType);

            switch (datatypeEnum)
            {
                case SQLiteDataTypeCollection.INTEGER:
                    try
                    {
                        return Int64.Parse(input).ToString();
                    }
                    catch { return null; }


                case SQLiteDataTypeCollection.NUMERIC:
                case SQLiteDataTypeCollection.REAL:
                    try
                    {
                        return Double.Parse(input).ToString();
                    }
                    catch { return null; }

                case SQLiteDataTypeCollection.DATETIME:
                    try
                    {
                        return DateTime.Parse(input).ToString();
                    }
                    catch { return null; }

                case SQLiteDataTypeCollection.NONE:
                    return input;

                case SQLiteDataTypeCollection.TEXT:
                default:
                    try
                    {
                        return Double.Parse(input).ToString();
                    }
                    catch
                    {
                        return "'" + input.Replace("'", "") + "'";
                    }
            }
        }

        public ISqlBuilder SqlBuilder
        {
            get
            {
                return SQLiteSqlBuilder.Instance;
            }
        }


        public void CreateDatabase(ISchemaCommand command, string databasename)
        {
            //do nothing here.
        }

        public void DropDatabase(ISchemaCommand command, string databasename)
        {
            if (!File.Exists(databasename))
                return;

            File.Delete(databasename);
        }
    }
}
